#include <iostream>
#include <coroutine>

struct Promise {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return std::suspend_always();
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    void unhandled_exception() {
        throw;
    }

    void return_value(int value) {
        mRet = value;
    }

    auto yield_value(int value) {
        mRet = value;
        return std::suspend_always();
    }

    int mRet;
};

struct Task {
    using promise_type = Promise;
    using BabyType = int;

    Task(std::coroutine_handle<promise_type> coroutine)
    : mCoroutine(coroutine)
    {}

    std::coroutine_handle<promise_type> mCoroutine;
};

Task hello() {
    std::cout << "hello" << std::endl;
    co_yield 32;
    std::cout << "return 32" << std::endl;
    co_yield 12;
    std::cout << "return 12" << std::endl;
    co_return 42;
}

int main() {
    std::cout << "Hello co_routine" << std::endl;
    Task t = hello();
    t.mCoroutine.resume();
    std::cout << "result is: " << t.mCoroutine.promise().mRet << std::endl;
    
    t.mCoroutine.resume();
    std::cout << "result is: " << t.mCoroutine.promise().mRet << std::endl;
    t.mCoroutine.resume();
    std::cout << "result is: " << t.mCoroutine.promise().mRet << std::endl;
    return 0;
}